package com.cbgolf.oa.manager;

import android.annotation.SuppressLint;
import android.util.Log;
import com.amap.api.maps.model.LatLng;
import com.cbgolf.oa.entity.ParkBean;
import com.cbgolf.oa.net.Web;
import com.cbgolf.oa.net.WebAPI;
import com.cbgolf.oa.service.LocationService;
import com.cbgolf.oa.util.DataUtil;
import com.cbgolf.oa.util.MapUtil;
import com.cbgolf.oa.util.Util;
import io.reactivex.CompletableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import ua.naiksoftware.stomp.Stomp;
import ua.naiksoftware.stomp.StompHeader;
import ua.naiksoftware.stomp.client.StompClient;

/**
 * @author lq
 * @date 2018/5/3
 */

public class WsStompManager {

  public static final String TAG = WsStompManager.class.getSimpleName();
  public StompClient mStompClient;
  public IWsManagerWaiter worker;
  //  private String msgUrl = "/queue/msg";
  private String locationUrl = "/oa/locations";
  //  private String mUrl = "/queue/m";
  private String locationTopic = "/queue/locations/";

  private ParkBean mData;
  private boolean isClosed;

  public String webSocketUrl;

  WsStompManager() {

  }

  private static class Inner {

    public static WsStompManager manager = new WsStompManager();
  }

  public static WsStompManager getInstance() {
    return Inner.manager;
  }


  @SuppressLint("CheckResult")
  public void init() {
    mStompClient = Stomp.over(Stomp.ConnectionProvider.JWS, getSocketUrl());
    List<StompHeader> list = new ArrayList<>();
    list.add(new StompHeader(Web.TOKEN, DataUtil.getToken()));
    mStompClient.connect(list);
    mStompClient.lifecycle()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(lifecycleEvent -> {
          switch (lifecycleEvent.getType()) {
            case OPENED:
              sendLatLngStomp();
              isClosed = false;
              Log.e(TAG, "----------------------Stomp connection opened");
              break;
            case ERROR:
              Log.e(TAG, "-------------------------Stomp connection error",
                  lifecycleEvent.getException());
//              reconnect();
              break;
            case CLOSED:
              Log.e(TAG, "--------------------Stomp connection closed");
              isClosed = true;
//              reconnect();
              break;
            default:
              break;
          }
        });

    mStompClient.topic(locationTopic + DataUtil.getParkId())
//    mStompClient.topic(locationTopic + DataUtil.getUserId())
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(topicMessage -> {
          Log.e(TAG, "useid--Received：" + topicMessage.getPayload());
          if (null != worker) {
            worker.onMessage(topicMessage.getPayload());
          }
        });
    mStompClient.topic(locationUrl, list)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(topicMessage -> {
          Log.e(TAG, "oa--Received： " + topicMessage.getPayload());
          if (null != worker) {
            worker.onMessage(topicMessage.getPayload());
          }
        });

  }

  public String getSocketUrl() {
    if (Util.isNull(webSocketUrl)) {
      webSocketUrl = new StringBuilder()
          .append("ws://")
          .append(WebAPI.IP)
          .append(WebAPI.web_socket)
          .toString();
    }
    return webSocketUrl;
  }

  @SuppressLint("CheckResult")
  public void sendLatLngStomp() {
    if (Util.isNull(DataUtil.getToken())) {
      disconnect();
      return;
    }
    List<LatLng> listRange = MapUtil.getListLatlngRange(mData);
    if (LocationService.getLat() > 0 && LocationService.getLon() > 0 && !MapUtil
        .isInRange(new LatLng(LocationService.getLat(), LocationService.getLon()), listRange)) {
      Log.e("outRange----------", "--------------");
      disconnect();
      return;
    }
    reconnect();
    JSONObject obj = new JSONObject();
    try {
      obj.put("userId", DataUtil.getUserId());
      obj.put("phone", DataUtil.getUserPhone());
      obj.put("courseId", DataUtil.getParkId());
      obj.put("lng", LocationService.getLon());
      obj.put("lat", LocationService.getLat());
    } catch (JSONException e) {
      e.printStackTrace();
    }
    Log.e("obj:", obj.toString());
    if (null != mStompClient) {
      mStompClient.send(locationUrl, obj.toString())
          .compose(applySchedulers())
          .subscribe(() -> {
            Log.e(TAG, "STOMP  send successfully---------------");
            if (null != worker) {
              worker.onSendOver(true);
            }
          }, throwable -> {
            Log.e(TAG, "Error send STOMP ----------", throwable);
            if (null != worker) {
              worker.onSendOver(false);
            }
          });
    }
  }


  public void disconnect() {
    try {
      if (null != mStompClient) {
        mStompClient.disconnect();
      }
    } catch (Exception e) {
    }
  }

  protected CompletableTransformer applySchedulers() {
    return upstream -> upstream
        .unsubscribeOn(Schedulers.newThread())
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());
  }

  public void release() {
    if (null != mStompClient) {
      mStompClient.disconnect();
      mStompClient = null;
    }
  }

  public void reconnect() {
    if (null == mStompClient || !mStompClient.isConnected() || isClosed) {
      try {
        init();
      } catch (Exception e) {
        Log.e("catch------------------", e.toString());
      }
    }
  }

  public boolean isConnecting() {
    return (null != mStompClient && mStompClient.isConnected() && !isClosed);
  }

  public WsStompManager setWorker(IWsManagerWaiter worker) {
    this.worker = worker;
    return this;
  }

  public WsStompManager setParkBean(ParkBean bean) {
    mData = bean;
    return this;
  }

  public interface IWsManagerWaiter {

    void onMessage(String msg);

    void onSendOver(boolean isSuccess);

    void onOutRange();
  }

}
